#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QImage>

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <errno.h>
#include <string.h>



MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

   // db_ops->lus_database_init();

    local_udp = new QUdpSocket(this);
    local_udp->bind(QHostAddress::LocalHost, 4399, QUdpSocket::ShareAddress);
    connect(local_udp,SIGNAL(readyRead()),this,SLOT(do_local_udp()));

    //my_tcp->server_ip = "192.168.137.1";
    my_tcp->aes_tcp_init();
    connect(my_tcp, SIGNAL(read_msg(QByteArray)), this, SLOT(read_tcp(QByteArray)));
    //connect(my_tcp, SIGNAL(aes_tcp_connected()), this, SLOT(connected_server()));
    //connect(my_tcp, SIGNAL(aes_tcp_disconnected()), this, SLOT(disconnected_server()));

   // cv_face_thread->get_image_flag = 1;
    connect(timer_4s, SIGNAL(timeout()), this,  SLOT(sensor_enable()));
    //timer_4s->start(4000);

    cv_face_thread->start();

    connect(cv_face_thread, SIGNAL(face_ok(QString)), this, SLOT(do_face_ok(QString)));

}

MainWindow::~MainWindow()
{
    delete ui;
}

void Thread_photo::run()
{

    pd.dev_name = "/dev/video0";

    int flag = init_dev(&pd);

    if (flag == -1) {
        // QMessageBox::information(this,tr("Tip"),tr("no device"));
        return ;
    }else if (flag == -2) {
        //QMessageBox::information(this,tr("Tip"),tr("device is wrong"));
        return;
    }else if (flag == -3) {
        //QMessageBox::information(this,tr("Tip"),tr("can not open device"));
        return ;
    }

    if(!cascade.load("haarcascade_frontalface_alt2.xml")){

        qDebug()<<"load face xml error";
        exit(-1);
    }

    model = FisherFaceRecognizer::create();
    //1.加载训练好的分类器
    model->read("MyFaceFisherModel.xml");// opencv2用load


    do{

/*        if(get_image_flag == 1){


            QString re =  predict();

            emit face_ok(re);

            get_image_flag = 0;


        }else{

            read_frame (&pd);
            msleep(10);
            return_data(&pd);

        }
*/


        QString re =  predict();

       emit face_ok(re);
        msleep(60);

    }while(1);


}

void MainWindow::read_tcp(QByteArray b_data)
{

//   qDebug()<< "#read_data        " <<b_data;

    do_cmd(b_data);
}

void MainWindow::do_cmd(QByteArray cmd)
{
  QDomDocument xml;
   xml.setContent(cmd);

   QDomElement rootnode = xml.documentElement();

   if(rootnode.tagName() == "init_msg"){

       QString id = rootnode.attributeNode("id").value();

       qDebug()<<"aes_tcp id = "<<id;

       return;
   }


   if(rootnode.tagName() == "user_msg"){

       if(rootnode.attributeNode("type").value() == "lab_msg"){

           if(rootnode.attributeNode("flag").value() == "cmd"){


                   cv_face_thread->get_image_flag = 1;

               }
               if(rootnode.attributeNode("body").value() == "alert_off"){


                 send_photo();
                   nrf_send(&cmd, sizeof(cmd));
               }

               return;
           }

           if(rootnode.attributeNode("flag").value() == "info"){

               QString info = rootnode.attributeNode("body").value();


               return;
           }

           if(rootnode.attributeNode("flag").value() == "task"){

               QString task = rootnode.attributeNode("body").value();


       }
       // qDebug()<<"user_msg";



   }

}

QString Thread_photo::predict(void)
{

    Mat frame;
    Mat gray;
    QImage image_raw;

    RNG g_rng(12345);
    std::vector<Rect> faces(0);//建立用于存放人脸的向量容器

        QDateTime time = QDateTime::currentDateTime();
        qDebug()<<time.toString("hh:mm:ss.zzz");

        qDebug()<<"start predict!";

#if 0
    QFile file("read.jpg");
    file.open(QIODevice::WriteOnly);
    read_frame (&pd);

    file.write((char *)pd.buffers[pd.buf.index].start,pd.buffers[pd.buf.index].length);
    file.close();

    image_raw.loadFromData((const uchar *)pd.buffers[pd.buf.index].start,pd.buffers[pd.buf.index].length);
    qDebug()<<image_raw.size();

    image_raw.load("/root/44.jpg");

    qDebug()<<image_raw.size();
    return "nop";
#endif

    do{
        read_frame (&pd);
        qDebug()<<"read ok";
        image_raw.loadFromData((const uchar *)pd.buffers[pd.buf.index].start,pd.buffers[pd.buf.index].length);
    }while(image_raw.size().width() == 0);

    qDebug()<<image_raw.size();

    //image_raw.save("jun.jpg");

    frame = QImage2cvMat(image_raw);

    return_data(&pd);
    //  CvMat cv_frame =  cvMat(320, 240, CV_8UC1, (uchar *)pd.buffers[pd.buf.index].start);

    //    Mat frame(cv_frame.rows, cv_frame.cols, cv_frame.type, cv_frame.data.fl);

   // imwrite("cvok.jpg", frame);
   // return "test";

    cvtColor(frame, gray, CV_RGB2GRAY);//测试图像必须为灰度图

    qDebug()<<"start face";

    equalizeHist(gray, gray); //变换后的图像进行直方图均值化处理
    //检测人脸
    cascade.detectMultiScale(gray, faces,
                             1.1, 4, 0
                             //|CV_HAAR_FIND_BIGGEST_OBJECT
                             | CV_HAAR_DO_ROUGH_SEARCH,
                             //| CV_HAAR_SCALE_IMAGE,
                             Size(30, 30), Size(500, 500));

    Mat* pImage_roi = new Mat[faces.size()];    //定以数组
    Mat face;
    Point text_lb;//文本写在的位置
    //框出人脸
    QString str;
    for (int i = 0; i < faces.size(); i++)
    {
        pImage_roi[i] = gray(faces[i]); //将所有的脸部保存起来
        text_lb = Point(faces[i].x, faces[i].y);
        if (pImage_roi[i].empty())
            continue;
        switch (Predict_labe(pImage_roi[i])) //对每张脸都识别
        {
        case 1:str = "JunChao_Zhao "; break;
        case 2:str = "My_girl"; break;
        case 3:str = "Xing_Yan"; break;
        default: str = "invade"; break;
        }
        Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));//所取的颜色任意值
        rectangle(frame, Point(faces[i].x, faces[i].y), Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height), color, 1, 8);//放入缓存
        putText(frame, str.toLatin1().data(), text_lb, FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));//添加文字
    }

    delete[]pImage_roi;

    imwrite("cvok.jpg", frame);

    image_my = cvMat2QImage(frame);

    QDateTime time2 = QDateTime::currentDateTime();
    qDebug()<<time2.toString("hh:mm:ss.zzz");

    qDebug()<<"face ="<< str;
    //ui->label->setPixmap(QPixmap::fromImage(image_raw));
    return str;
}

int Thread_photo::Predict_labe(Mat src_image)  //识别图片
{
    Mat face_test;
    int predict = 0;
    //截取的ROI人脸尺寸调整
    if (src_image.rows >= 120)
    {
        //改变图像大小，使用双线性差值
        cv::resize(src_image, face_test, Size(92, 112));

    }
    //判断是否正确检测ROI
    if (!face_test.empty())
    {
        //测试图像应该是灰度图
        predict = model->predict(face_test);
    }
    return predict;
}

QImage Thread_photo::cvMat2QImage(const cv::Mat& mat)
{

    if(mat.type() == CV_8UC1)
    {
        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
        image.setColorCount(256);
        for(int i = 0; i < 256; i++)
        {
            image.setColor(i, qRgb(i, i, i));
        }
        uchar *pSrc = mat.data;
        for(int row = 0; row < mat.rows; row ++)
        {
            uchar *pDest = image.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return image;
    }
    else if(mat.type() == CV_8UC3)
    {
        const uchar *pSrc = (const uchar*)mat.data;
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }
    else if(mat.type() == CV_8UC4)
    {
        const uchar *pSrc = (const uchar*)mat.data;
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image.copy();
    }
    else
    {
        qDebug() << "ERROR: Mat could not be converted to QImage";
        return QImage();
    }


}

Mat Thread_photo::QImage2cvMat(QImage image)
{
    cv::Mat mat;
    switch(image.format()) {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:

        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
        break;

    case QImage::Format_RGB888:

        mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
        cv::cvtColor(mat, mat, CV_BGR2RGB);
        break;

    case QImage::Format_Indexed8:

        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        break;
    }

    return mat;
}

void MainWindow::do_face_ok(QString str)
{


    QPixmap pix = QPixmap::fromImage(cv_face_thread->image_my);

    ui->label_photo->setPixmap(pix);

    /*
    QImage image_my;
    image_my.load("/root/lab/cvok.jpg");
    qDebug()<< "image my size "<<image_my.size();

       QByteArray ba;

       QBuffer buf(&ba);

       image_my.save(&buf,"JPG",50);

       QByteArray xml_info;
       xml_info = "<user_msg type=\"tank_image\" ch=\"xxx\" body=\"";

       QString id = QString::number(f_id);
       xml_info.replace("xxx", id.toLatin1().data());

       QByteArray hexed = ba.toBase64();
       xml_info += hexed;

       xml_info += "\" />";

       my_tcp->sendMessage(xml_info, ENCRYPT_NO);

    qDebug()<<"send face tcp ok";
*/
}

void MainWindow::send_photo()
{

      QImage image_my;
    image_my.load("/root/lab/cvok.jpg");
    qDebug()<< "image my size "<<image_my.size();

       QByteArray ba;

       QBuffer buf(&ba);

       image_my.save(&buf,"JPG",50);

       QByteArray xml_info;
       xml_info = "<user_msg type=\"tank_image\" ch=\"xxx\" body=\"";

       QString id = QString::number(f_id);
       xml_info.replace("xxx", id.toLatin1().data());

       QByteArray hexed = ba.toBase64();
       xml_info += hexed;

       xml_info += "\" />";

       my_tcp->sendMessage(xml_info, ENCRYPT_NO);

    qDebug()<<"send face tcp ok";



}
void MainWindow::do_local_udp()
{

    while(local_udp->hasPendingDatagrams())  //拥有等待的数据报
    {
        QByteArray datagram; //拥于存放接收的数据报
        //让datagram的大小为等待处理的数据报的大小，这样才能接收到完整的数据
        datagram.resize(local_udp->pendingDatagramSize());
        //接收数据报，将其存放到datagram中
        local_udp->readDatagram(datagram.data(),datagram.size());
        //将数据报内容显示出来


        uint8_t type_flag = ((uint8_t *)datagram.data())[0];

        qDebug() << "type flag " << type_flag;


    }


}

/*发送命令*/
void MainWindow::nrf_send(void * data, uint16_t size)
{



}

void MainWindow::sensor_enable()
{


}

